package com.lx.util;

import com.lx.entity.XmlNode;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * xpath解析xml
 *
 * <pre>
 *     文档地址：
 *     http://www.w3school.com.cn/xpath/index.asp
 * </pre>
 * @author L.cm
 */
class XmlHelper {
    public static Map<String , String> xmlToStringMap(String xml){
        return new XmlNode(create(xml).getDocumentElement()).getStringMap();
    }
    public static Map<String , XmlNode> xmlToMap(String xml){
        return new XmlNode(create(xml).getDocumentElement()).getMap();
    }
    public static List<XmlNode> xmlToList(String xml){
        return new XmlNode(create(xml).getDocumentElement()).getList();
    }
    public static List<Map<String,String>> xmlToStringMapList(String xml){
        return new XmlNode(create(xml).getDocumentElement()).getStringMapList();
    }

    private static Document create(String xmlStr) {
        return create(new InputSource(new StringReader(xmlStr.trim())));
    }

    private static Document create(InputSource inputSource){
        try {
            DocumentBuilderFactory dbf = getDocumentBuilderFactory();
            dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
            dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            dbf.setXIncludeAware(false);
            dbf.setExpandEntityReferences(false);
            DocumentBuilder db = dbf.newDocumentBuilder();
            return db.parse(inputSource);
        } catch (ParserConfigurationException | SAXException | IOException e) {
            throw new RuntimeException(e);
        }
    }



    private static DocumentBuilderFactory getDocumentBuilderFactory() {
        return XmlHelperHolder.documentBuilderFactory;
    }

    private static XPathFactory getXpathFactory() {
        return XmlHelperHolder.xPathFactory;
    }

    /**
     * 内部类单例
     */
    private static class XmlHelperHolder {
        private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        private static XPathFactory xPathFactory = XPathFactory.newInstance();
    }

    public static String toXml(StringBuffer xml ,Collection params, String label, String childLabel, boolean skipEmpty) {
        if (LX.isEmpty(params)){
            return "";
        }
        if (xml == null){
            xml = new StringBuffer();
        }
        if (LX.isNotEmpty(label)){
            xml.append("<").append(label).append(">");
        }
        for (Object value : params) {
            if (value instanceof Map){
                toXml(xml,(Map<String, Object>) value,childLabel,skipEmpty);
            }else{
                xml.append("<").append(childLabel).append(">");
                xml.append(LX.str(value));
                xml.append("</").append(childLabel).append(">");
            }
        }
        if (LX.isNotEmpty(label)){
            xml.append("</").append(label).append(">");
        }
        return xml.toString();
    }
    //说明: 循环拼接xml
    /** @author ylx 2022/6/7 11:48 */
    public static String toXml(StringBuffer xml ,Map<String, Object> params, String label, boolean skipEmpty) {
        if (xml == null){
            xml = new StringBuffer();
        }
        if (LX.isNotEmpty(label)){
            xml.append("<").append(label).append(">");
        }
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            // 略过空值
            if (skipEmpty && LX.isEmpty(value)) {
                continue;
            }
            if (value instanceof Map){
                toXml(xml,(Map<String, Object>) value,key,skipEmpty);
            }else{
                xml.append("<").append(key).append(">");
                xml.append(value);
                xml.append("</").append(key).append(">");
            }
        }
        if (LX.isNotEmpty(label)){
            xml.append("</").append(label).append(">");
        }
        return xml.toString();
    }



}
